/*
 *  linux/kernel/sys.c
 *
 *  (C) 1991  Linus Torvalds
 */

#include <errno.h>

#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <sys/times.h>
#include <sys/utsname.h>
struct linux_dirent {
 	long d_ino;
 	off_t d_off;
 	unsigned short d_reclen;
 	char d_name[14];
};
int sys_ftime()
{
	return -ENOSYS;
}

int sys_break()
{
	return -ENOSYS;
}

int sys_ptrace()
{
	return -ENOSYS;
}

int sys_stty()
{
	return -ENOSYS;
}

int sys_gtty()
{
	return -ENOSYS;
}

int sys_rename()
{
	return -ENOSYS;
}

int sys_prof()
{
	return -ENOSYS;
}

int sys_setregid(int rgid, int egid)
{
	if (rgid>0) {
		if ((current->gid == rgid) || 
		    suser())
			current->gid = rgid;
		else
			return(-EPERM);
	}
	if (egid>0) {
		if ((current->gid == egid) ||
		    (current->egid == egid) ||
		    suser()) {
			current->egid = egid;
			current->sgid = egid;
		} else
			return(-EPERM);
	}
	return 0;
}

int sys_setgid(int gid)
{
/*	return(sys_setregid(gid, gid)); */
	if (suser())
		current->gid = current->egid = current->sgid = gid;
	else if ((gid == current->gid) || (gid == current->sgid))
		current->egid = gid;
	else
		return -EPERM;
	return 0;
}

int sys_acct()
{
	return -ENOSYS;
}

int sys_phys()
{
	return -ENOSYS;
}

int sys_lock()
{
	return -ENOSYS;
}

int sys_mpx()
{
	return -ENOSYS;
}

int sys_ulimit()
{
	return -ENOSYS;
}

int sys_time(long * tloc)
{
	int i;

	i = CURRENT_TIME;
	if (tloc) {
		verify_area(tloc,4);
		put_fs_long(i,(unsigned long *)tloc);
	}
	return i;
}

/*
 * Unprivileged users may change the real user id to the effective uid
 * or vice versa.
 */
int sys_setreuid(int ruid, int euid)
{
	int old_ruid = current->uid;
	
	if (ruid>0) {
		if ((current->euid==ruid) ||
                    (old_ruid == ruid) ||
		    suser())
			current->uid = ruid;
		else
			return(-EPERM);
	}
	if (euid>0) {
		if ((old_ruid == euid) ||
                    (current->euid == euid) ||
		    suser()) {
			current->euid = euid;
			current->suid = euid;
		} else {
			current->uid = old_ruid;
			return(-EPERM);
		}
	}
	return 0;
}

int sys_setuid(int uid)
{
/*	return(sys_setreuid(uid, uid)); */
	if (suser())
		current->uid = current->euid = current->suid = uid;
	else if ((uid == current->uid) || (uid == current->suid))
		current->euid = uid;
	else
		return -EPERM;
	return(0);
}

int sys_stime(long * tptr)
{
	if (!suser())
		return -EPERM;
	startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
	return 0;
}

int sys_times(struct tms * tbuf)
{
	if (tbuf) {
		verify_area(tbuf,sizeof *tbuf);
		put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime);
		put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime);
		put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime);
		put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime);
	}
	return jiffies;
}

int sys_brk(unsigned long end_data_seg)
{
	if (end_data_seg >= current->end_code &&
	    end_data_seg < current->start_stack - 16384)
		current->brk = end_data_seg;
	return current->brk;
}

/*
 * This needs some heave checking ...
 * I just haven't get the stomach for it. I also don't fully
 * understand sessions/pgrp etc. Let somebody who does explain it.
 */
int sys_setpgid(int pid, int pgid)
{
	int i;

	if (!pid)
		pid = current->pid;
	if (!pgid)
		pgid = current->pid;
	for (i=0 ; i<NR_TASKS ; i++)
		if (task[i] && task[i]->pid==pid) {
			if (task[i]->leader)
				return -EPERM;
			if (task[i]->session != current->session)
				return -EPERM;
			task[i]->pgrp = pgid;
			return 0;
		}
	return -ESRCH;
}

int sys_getpgrp(void)
{
	return current->pgrp;
}

int sys_setsid(void)
{
	if (current->leader && !suser())
		return -EPERM;
	current->leader = 1;
	current->session = current->pgrp = current->pid;
	current->tty = -1;
	return current->pgrp;
}

int sys_getgroups()
{
	return -ENOSYS;
}

int sys_setgroups()
{
	return -ENOSYS;
}

int sys_uname(struct utsname * name)
{
	static struct utsname thisname = {
		"linux .0","nodename","release ","version ","machine "
	};
	int i;

	if (!name) return -ERROR;
	verify_area(name,sizeof *name);
	for(i=0;i<sizeof *name;i++)
		put_fs_byte(((char *) &thisname)[i],i+(char *) name);
	return 0;
}

int sys_sethostname()
{
	return -ENOSYS;
}

int sys_getrlimit()
{
	return -ENOSYS;
}

int sys_setrlimit()
{
	return -ENOSYS;
}

int sys_getrusage()
{
	return -ENOSYS;
}

int sys_gettimeofday()
{
	return -ENOSYS;
}

int sys_settimeofday()
{
	return -ENOSYS;
}


int sys_umask(int mask)
{
	int old = current->umask;

	current->umask = mask & 0777;
	return (old);
}
int sys_sleep(unsigned int seconds)
{
        sys_alarm(seconds);
        sys_pause();
        if(sys_signal(SIGALRM,SIG_IGN)==-1)
                return -1;
        return 0;
}
long sys_getcwd(char * buf, size_t size)
{
	char buf1[1024];
	char buf2[1024];
	struct buffer_head *bh;
	struct m_inode *minode,*preminode,*pwd,*root;    
    struct dir_entry *de,*prede;  
	pwd=current->pwd;root=current->root;
	minode=pwd;
	do
	{
		bh = bread(minode->i_dev, minode->i_zone[0]);   
        prede = (struct dir_entry *)(bh->b_data+sizeof(struct dir_entry));
		preminode=iget(minode->i_dev,prede->inode);bh=bread(preminode->i_dev, preminode->i_zone[0]);
		int nowpos=2*sizeof(struct dir_entry);
		de = (struct dir_entry *)(bh->b_data+nowpos);
		while(de->inode)
		{
			if(de->inode==minode->i_num)
			{
				strcpy(buf1,"/");
				strcat(buf1,de->name);
				strcat(buf1,buf2);
				strcpy(buf2,buf1);
				break;
			}
			nowpos=nowpos+sizeof(struct dir_entry);de = (struct dir_entry *)(bh->b_data+nowpos);
		}
		minode=preminode;
	} while (minode!=root);
	int i=0;
	while(buf2[i])
	{
		put_fs_byte(buf2[i],buf+i);
		i++;
	}
	return buf;
}
int sys_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count)
{
	int globalpos=0;
	int dei=0,i;
	int lenth=sizeof(struct linux_dirent);
	struct buffer_head * bh;
	struct dir_entry * de;
	struct super_block * sb;
	struct linux_dirent temp;
	struct m_inode *minode=current->filp[fd]->f_inode;
	bh= bread(minode->i_dev,minode->i_zone[0]);
	de=(struct dir_entry*)bh->b_data;
	while(de[dei].inode)
	{
		if (globalpos +lenth > count)
			break;
		temp.d_ino = de[dei].inode;
		temp.d_off = 0;
		temp.d_reclen = lenth;
		for (i = 0; i < 14; i++)
		{
			temp.d_name[i] = de[dei].name[i];
		}
		for(i = 0;i <lenth; i++){
			put_fs_byte(((char *)(&temp))[i],(char *)dirp + globalpos);
			globalpos++;
		}
		dei++;
	}
	return globalpos;
}
int sys_pipe2(void)
{
	return -1;
}
int sys_mmap(void)
{
	return -1;
}
int sys_munmap(void)
{
	return -1;
}
int sys_clone(void)
{

	return -1;
}